/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*				PROJETO III - PROGRAMACAO CONCORRENTE
*							 SSC0143				  PROF.: JULIO ESTRELLA
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*	DESCRICAO:	SMOOTHING DE IMAGENS OPEN MPI E CUDA
*
*	LINGUAGEM:	C
*				
*	GRUPO - 8:	CARLOS HUMBERTO DOS SANTOS BAQUETA			  NUSP: 7987456
*	(TURMA-A)	RICARDO    ISSAMU   FUKUDA   GUNZI			  NUSP: 7986729
*				
*	
*	ENTREGA  :	07/12/2014									  BCC-012
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <stdio.h>
#include <stdlib.h> 
#include <string.h> 
#include <math.h> 
// Library that allows to use time functions to evaluate the performance
#include <sys/time.h>

#define SMOOTH_LEVEL 5


/// executa smooth sequencial na cpu, para cada matriz de cor (r, g, b)
void execSeq(int width, int height, unsigned char *rgb_[3], unsigned char *out_[3]) {
	int i, j, m, n, k, soma;
	int width2 = width + 4;
	
	for(k=0; k < 3; k++){
		for(i=0; i < height; i++){
			unsigned int inicY = i-2;
			unsigned int limitY = i+3;
									
			for(j=0; j < width; j++){
				unsigned int inicX = j-2;
				unsigned int limitX = j+3;
										
				soma=0;	
				for(n = inicY; n < limitY; n++){
					for(m = inicX; m < limitX; m++){
						soma += rgb_[k][(n + 2) * width2 + m + 2];
					}
				}
				out_[k][i*width + j] = (unsigned char)((unsigned int)soma/25);
			}
		}
	}
}

//
int main(int argc, char  **argv)
{
	FILE *fp=NULL;
	int numExec=0;
	char *arq_name;
	int i, j, k, width, height, width2, height2, maxValue, value, soma, rc;

  	unsigned char *rgb[3]={NULL, NULL, NULL}, *out[3]={NULL, NULL, NULL};
	char format[3];

	double time_start, time_end;
	struct timeval tv, tve;
	struct timezone tz, tze;


	gettimeofday(&tv, &tz);
	time_start = (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
	if (argc > 2){
		numExec = atoi(argv[1]);
		// strcpy(arq_name, argv[2]);
		arq_name = argv[2];
	}else{
		fprintf(stderr, "Informe o numero de simulacoes em argv[1] e o nome do arquivo de saida em argv[2].\n");
	}

	/// leitura do cabeçalho do arquivo
	scanf("%s", format);
	scanf("%d %d %d", &width, &height, &maxValue);
	
	/// erro: formato incorreto, nao é rgb.
	if(strcmp(format, "P3")){
		return -1;
	}
	
	/// erro: nao é unsigned char.
	if(maxValue > 255){
		return -1;
	}
	
	width2 = width+(2*((int)SMOOTH_LEVEL/2));
	height2 = height+(2*((int)SMOOTH_LEVEL/2));

	// Aloca as matrizes rgb
	for(i=0; i < 3; i++){
		rgb[i] = (unsigned char*) calloc(height2*width2, sizeof(unsigned char));
		out[i] = (unsigned char*) calloc(height*width, sizeof(unsigned char)); //p/ seq
	}
	
	// Le os valores rgb de cada pixel da imagem e coloca na matriz correspondente
	for(i=0; i < height; i++){
		for(j=0; j < width; j++){
			for(k=0; k < 3; k++){
				scanf("%d",  &value);
				rgb[k][(i+2)*width2 + j + 2] = (unsigned char)value;
			}
		}
	}

	if ((fp = fopen(arq_name, "a+")) == NULL){
      	fprintf(stderr, "Error opening outfile: %s\n", arq_name);
    }else{
    	
    }

	/// Execucao do sequencial:
	for (i=0; i<numExec; i++){
		execSeq(width, height, rgb, out);
		gettimeofday(&tv, &tz);
	}

	time_end = (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
	fprintf(fp, "%.10f\n", (time_end-time_start));

	// Geração da imagem após oi smoothing
	printf("P3\n%d %d\n%d\n", width, height, maxValue);	
	for(i=0; i < height; i++){
		for(j=0; j < width; j++){
			for(k=0; k < 3; k++){
				printf("%d ", (unsigned char)out[k][i*width + j]);
			}
		}
		printf("\n");
	}

    fclose(fp);
	return 0;
}